// On-disk file system format.
// Both the kernel and user programs use this header file.
#pragma once
#include "../../include/types.h"
#include "../../include/riscv.h"
#include "../proc/spinlock.h"
#include "../proc/proc.h"
#include "sleeplock.h"
#include "stat.h"
#include "string.h"
#define ROOTINO  1   // root i-number
#define BSIZE 1024  // block size

// Disk layout:
// [ boot block | super block | log | inode blocks |
//                                          free bit map | data blocks]
//
// mkfs computes the super block and builds an initial file system. The
// super block describes the disk layout:
struct superblock {
  uint32 magic;        // Must be FSMAGIC
  uint32 size;         // Size of file system image (blocks)
  uint32 nblocks;      // Number of data blocks
  uint32 ninodes;      // Number of inodes.
  uint32 nlog;         // Number of log blocks
  uint32 logstart;     // Block number of first log block
  uint32 inodestart;   // Block number of first inode block
  uint32 bmapstart;    // Block number of first free map block
};

#define FSMAGIC 0x10203040

#define NDIRECT 12
#define NINDIRECT (BSIZE / sizeof(uint32))
#define MAXFILE (NDIRECT + NINDIRECT)

// On-disk inode structure
struct dinode {
  short type;           // File type
  short major;          // Major device number (T_DEVICE only)
  short minor;          // Minor device number (T_DEVICE only)
  short nlink;          // Number of links to inode in file system
  uint32 size;            // Size of file (bytes)
  uint32 addrs[NDIRECT+1];   // Data block addresses
};

// Inodes per block.
#define IPB           (BSIZE / sizeof(struct dinode))

// Block containing inode i
#define IBLOCK(i, sb)     ((i) / IPB + sb.inodestart)

// Bitmap bits per block
#define BPB           (BSIZE*8)

// Block of free map containing bit for block b
#define BBLOCK(b, sb) ((b)/BPB + sb.bmapstart)

// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14

// The name field may have DIRSIZ characters and not end in a NUL
// character.
struct dirent {
  uint16 inum;
  char name[DIRSIZ] __attribute__((nonstring));
};

 void
readsb(int dev, struct superblock *sb);

// Init fs
void
fsinit(int dev) ;

// Zero a block.
 void
bzero(int dev, int bno);

// Allocate a block.
 uint32
balloc(uint32 dev);

// Free a block.
 void
bfree(int dev, uint32 b);

void
iinit();

struct inode*
ialloc(uint32 dev, short type);


// Copy a modified in-memory inode to disk.
// Must be called after every change to an ip->xxx field
// that lives on disk.
// Caller must hold ip->lock.
void
iupdate(struct inode *ip);

// Increment reference count for ip.
// Returns ip to enable ip = idup(ip1) idiom.
struct inode*
idup(struct inode *ip);

// Lock the given inode.
// Reads the inode from disk if necessary.
void
ilock(struct inode *ip);

// Unlock the given inode.
void
iunlock(struct inode *ip);

// Drop a reference to an in-memory inode.
// If that was the last reference, the inode table entry can
// be recycled.
// If that was the last reference and the inode has no links
// to it, free the inode (and its content) on disk.
// All calls to iput() must be inside a transaction in
// case it has to free the inode.
void
iput(struct inode *ip);

// Common idiom: unlock, then put.
void
iunlockput(struct inode *ip);

void
ireclaim(int dev);

 uint32
bmap(struct inode *ip, uint32 bn);

void
itrunc(struct inode *ip);

void
stati(struct inode *ip, struct stat *st);

int
readi(struct inode *ip, int user_dst, uint64 dst, uint32 off, uint32 n);

int
writei(struct inode *ip, int user_src, uint64 src, uint32 off, uint32 n);


int
namecmp(const char *s, const char *t);

struct inode*
dirlookup(struct inode *dp, char *name, uint32 *poff);

int
dirlink(struct inode *dp, char *name, uint32 inum);

 char*
skipelem(char *path, char *name);

 struct inode*
namex(char *path, int nameiparent, char *name);

struct inode*
namei(char *path);

struct inode*
nameiparent(char *path, char *name);